
package ec.edu.ups.cidi.siia.plamdep.ejecutor;

import java.util.ArrayList;
import java.util.List;
import ec.edu.ups.cidi.siia.plamdep.cargadocumentos.Documento;
import ec.edu.ups.cidi.siia.plamdep.comunicacionweb.ConexionWeb;
import ec.edu.ups.cidi.siia.plamdep.comunicacionweb.Resultado;
import ec.edu.ups.cidi.siia.plamdep.ejecutor.GestionAlgoritmos.AlgComparacionContainer;
import ec.edu.ups.cidi.siia.plamdep.ejecutor.GestionAlgoritmos.AlgExtractorContainer;
import ec.edu.ups.cidi.siia.plamdep.ejecutor.GestionAlgoritmos.CargaJAR;
import ec.edu.ups.cidi.siia.plamdep.ejecutor.GestionAlgoritmos.GestorAlgoritmos;
import ec.edu.ups.cidi.siia.plamdep.moduloweb.jms.SolicitudAnalisisJMS;
import ec.edu.ups.cidi.siia.plamdep.utils.configuracion.ConfiguracionConexionWeb;
import ec.edu.ups.cidi.siia.plamdep.utils.configuracion.ConfiguracionGlobal;
import ec.edu.ups.cidi.siia.plamdep.utils.interfaces.*;

public class Ejecutor{
    
    private static CargaJAR loader=new CargaJAR();
    static Ejecutor instanciaEjecutor;
    private ArrayList<Fuente> fuentes=new ArrayList<Fuente>();
    /**
     * Arranca los servicios y carga los algoritmos con los que trabajara
     * @param algscom
     * @param algsex
     */
    public Ejecutor( List<AlgComparacionContainer> algscom, List<AlgExtractorContainer> algsex )
    {
    	instanciaEjecutor=this;
    	/**Carga la configuracion de la plataforma*/
    	ConfiguracionGlobal.cargarConfiguracion();
    	/** arranca los servicios*/
        Servicios.arrancarAnalizadorLexico();
        Servicios.arrancarBuscadorWeb();
        cargarAlgoritmos(algscom, algsex);
    	
    	
    	
    }
    public static void cargarAlgoritmos(List<AlgComparacionContainer> algscom, List<AlgExtractorContainer> algsex)
    {
    	GestorAlgoritmos.quitarAlgoritmos();
    	/** carga algortimos de comparacion */
    	for(AlgComparacionContainer alg:algscom)
    		 loader.loadAlgoritmoComparacion(alg);
    		
    	
    	/** carga algortimos de comparacion */
    	for(AlgExtractorContainer alg: algsex)
    		loader.loadAlgoritmoExtraccion(alg);
    }
    /**
     * Metodo que realiza el proceso de analisis
     * @param docAnalizarPath
     * @param algComparacion
     * @param algExtraccion
     * @param buscarInternet
     * @param fuentesLocales
     * @return
     */
    public List<ResultadoFinal> analizar(String docAnalizarPath,String algComparacion, String algExtraccion, boolean buscarInternet, List<String> fuentesLocales)
    {
        
    	
    	//Fase 1: Carga el documento
    	Documento docAnalizar=new Documento(docAnalizarPath);
    	ArrayList<Fuente> fuentes=new ArrayList<Fuente>();
    	List<ResultadoFinal> resultados=new ArrayList();
    	
    	
    	//Fase 2 Busca y Carga las posibles fuentes 
    	///////////////////////////////////////////////////////
        if(buscarInternet)//carga las posibles fuentes de internet
           fuentes=this.buscarFuentesInternet(algExtraccion, docAnalizar.getContenido());
       
        ArrayList<Fuente> locales=this.buscarFuentesLocales(fuentesLocales);//carga las posibles fuentes locales
        for(Fuente f:locales) fuentes.add(f);
      
        
        //Fase 3 Ejecuta el algoritmo de deteccion por cada fuente
        ////////////
        for(Fuente f:fuentes)
        {
        	System.out.println("Comparando con documento:"+f.getRutaOrigen());
	        AlgoritmoComparacion alComparacion= GestorAlgoritmos.getAlgoritmoComparacion(algComparacion);
	        alComparacion.setFuente(f);
	        alComparacion.setTextoAnalizar(docAnalizar.getContenido());
	        alComparacion.ejecutar();
		    ResultadoFinal result= alComparacion.getResultadoFinal();
		    result.setFuente(f);
		    resultados.add(result);
        }
        return resultados;
        
    }
    
    private   ArrayList<Fuente> buscarFuentesInternet(String algExtraccion, String contenido)
    {
    	
    	System.out.println("Buscando fuentes de internet con alg:"+algExtraccion);
    	fuentes=new ArrayList<Fuente>();
        AlgoritmoExtraccion extractor= GestorAlgoritmos.getAlgoritmoExtraccion(algExtraccion);
         if(extractor!= null)
         { 
		         extractor.setTextoToAnalizar(contenido);
		         extractor.ejecutar();
		         ConexionWeb downloader=Servicios.getDownloader();
		         List<Keyword> keywords=extractor.getPalabrasClave();
		         List<DescargasManager> descargas=new ArrayList<DescargasManager>();
		         for(Keyword key:keywords) //prepara las conexiones para todas las descargas
		         {
		            ArrayList<String> busqueda=Servicios.getBuscadorWeb().buscar(key.getKeyword());
		            System.out.println("\n\nPosibles fuentes para:"+key);
		            for(String url:busqueda)
		                if(!contains(fuentes, url))
		                {
		                	  System.out.println(url);
		                	  ConexionWeb con=Servicios.getBuscadorWeb();
		                	  con.setUrlDescargar(url);
		                	  descargas.add(new DescargasManager(con,key));
		                }
		         }
		         for(int i=0;i<descargas.size();i++)
		         {
		        	 //inicializa las descargas paralelas
		        	 for(int j=0;j<ConfiguracionConexionWeb.descargasParalelas;j++)
		        	 {
		        		 if(i<descargas.size())
		        		 {
		        			 descargas.get(i).descargar();
		        			 i++;
		        		 }
		        		 else break;
		        	 }
		        	 //espera un tiempo antes de inicializar las siguientes descargas
		        	 try {	Thread.sleep(ConfiguracionConexionWeb.timeoutDescarga);	} catch (InterruptedException e) {	}
		         }	 
		         for(DescargasManager d:descargas) //mata los hilos de descargas por si hay resagados
		         {
		        	 d.getProceso().stop();
		        	 
		         }
		         
		         
         }else System.err.println("Algoritmo de extraccion no encontrado..");
        	 
         
         return fuentes;   
    }
    private ArrayList<Fuente> buscarFuentesLocales(List<String> fuentesLocales)
    {
    	 
        ArrayList<Fuente> fuentes=new ArrayList<Fuente>();
            if(fuentesLocales!=null) 
        	for(String ruta:fuentesLocales)
             {
            	 System.out.println("cargando fuente local:"+ruta);
            	 fuentes.add(new Fuente(new Documento(ruta).getContenido(),"local",ruta));
             }
         
         return fuentes;  
    }
     
    public String extraerNoCitado()
    {
    	
    	return "";
    }
    public boolean contains(ArrayList<Fuente> fuentes, String url)
    {
        for(Fuente f:fuentes)
            if(f.getRutaOrigen().equalsIgnoreCase(url))
                   return true;
        return false;
    }

        public 	List<ResultadoFinal> analisisTextual(SolicitudAnalisisJMS sol)
	{
		
		System.out.println("\n\n\n*******************************Iniciando analisis");
		List<ResultadoFinal> result=null;
			try{
			result= analizar(sol.getRutaArchivoSospechoso(),sol.getCodigoAlgoritmoComparacion(),sol.getCodigoAlgoritmoExtraccion(),sol.isBusquedaWeb(), sol.getFuentesLocales());
			}catch(Exception ex){
				System.out.println("Error al analizar..");
				result=new ArrayList();
				ex.printStackTrace();
				

			}
			System.out.println("\n*******************************Fin del analisis\n\n");
		
		return result;
	}
    
        private class DescargasManager  implements Runnable 
        {
        	private ConexionWeb conexion;
        	private Thread proceso;
        	private Keyword key;
        	public DescargasManager(ConexionWeb conexion,Keyword key)
        	{
        		this.conexion=conexion;
        		this.key=key;
        	}
        	public void descargar()
        	{
        		proceso=new Thread(this);
        		proceso.start();
        	}

    		public void run() 
    		{
    				Resultado r=conexion.descargarContenido();
    				Fuente f=new Fuente();
    				f.setContenido(r.getContenido());
    				f.setRutaOrigen(r.getLink());
    				f.setTipo("Web");
    				f.setMetadatos(r.getMetadatos());
    				f.setKey(key);
    				fuentes.add(f);
    		}

    		public Thread getProceso() {
    			return proceso;
    		}

    		public void setProceso(Thread proceso) {
    			this.proceso = proceso;
    		}
        	
        }

}
